
#include "GlobalHead.h"
#include "Gui/Gui_Document.h"
#include "View.h"
#include "App/App_Application.h"
#include "View3DInventor.h"
#include "MainWindow.h"
#include "CustomPlayer.h"
#include "Command.h"
#include "FileDialog.h"
#include "DocumentObject.h"
#include "ViewProviderDocumentObject.h"
#include "View3DInventorViewer.h"
#include "Gui_Application.h"
#include "VtRender.h"

#include <Base/Console.h>
//#include <Base/Exception.h>
//#include <Base/Matrix.h>
#include <Base/Reader.h>
#include <Base/Writer.h>

using namespace Gui;
using namespace App;
namespace Gui
{

	// Pimpl class
	struct DocumentP
	{
//		Thumbnail thumb;
		int        _iWinCount;
		int        _iDocId;
		bool       _isClosing;
		bool       _isModified;
		ViewProvider*   _pcInEdit;
		Gui_Application*    _pcAppWnd;
		// the doc/Document
		App::Document*  _pcDocument;
		/// List of all registered views
		std::list<Gui::BaseView*> baseViews;
		/// List of all registered views
		std::list<Gui::BaseView*> passiveViews;
		std::map<const App::DocumentObject*,ViewProviderDocumentObject*> _ViewProviderMap;
		std::map<std::string,ViewProvider*> _ViewProviderMapAnnotation;

		typedef boost::signals::connection Connection;
		Connection connectNewObject;
		Connection connectDelObject;
		Connection connectCngObject;
		Connection connectRenObject;
		Connection connectActObject;
		Connection connectSaveDocument;
		Connection connectRestDocument;
		Connection connectLoadDocument;
	};

}

int Gui_Document::_iDocCount = 0;

Gui_Document::Gui_Document(App::Document* pcDocument,Gui_Application * app)
{

	d = new DocumentP;
	d->_iWinCount = 1;
	// new instance
	d->_iDocId = (++_iDocCount);
	d->_isClosing = false;
	d->_isModified = false;
	d->_pcAppWnd = app;
	d->_pcDocument = pcDocument;
	d->_pcInEdit = 0;

	// Setup the connections
	d->connectNewObject = pcDocument->signalNewObject.connect
		(boost::bind(&Gui::Gui_Document::slotNewObject, this, _1));
	d->connectDelObject = pcDocument->signalDeletedObject.connect
		(boost::bind(&Gui::Gui_Document::slotDeletedObject, this, _1));
	d->connectCngObject = pcDocument->signalChangedObject.connect
		(boost::bind(&Gui::Gui_Document::slotChangedObject, this, _1, _2));
	d->connectRenObject = pcDocument->signalRenamedObject.connect
		(boost::bind(&Gui::Gui_Document::slotRenamedObject, this, _1));
	d->connectActObject = pcDocument->signalActivatedObject.connect
		(boost::bind(&Gui::Gui_Document::slotActivatedObject, this, _1));
 	d->connectSaveDocument = pcDocument->signalSaveDocument.connect
 		(boost::bind(&Gui::Gui_Document::Save, this, _1));
 	d->connectRestDocument = pcDocument->signalRestoreDocument.connect
 		(boost::bind(&Gui::Gui_Document::Restore, this, _1));
	d->connectLoadDocument =GetApp_Application().signalRestoreDocument.connect
		(boost::bind(&Gui::Gui_Document::slotRestoredDocument, this, _1));

	// pointer to the python class
	// NOTE: As this Python object doesn't get returned to the interpreter we
	// mustn't increment it (Werner Jan-12-2006)
//	_pcDocPy = new Gui::DocumentPy(this);

	if (GetApp_Application().GetParameterGroupByPath
		("User parameter:BaseApp/Preferences/Document")->GetBool("UsingUndo",true))
		d->_pcDocument->setUndoMode(1);
}

Gui_Document::~Gui_Document(void)
{

	// disconnect everything to avoid to be double-deleted
	// in case an exception is raised somewhere
	d->connectNewObject.disconnect();
	d->connectDelObject.disconnect();
	d->connectCngObject.disconnect();
	d->connectRenObject.disconnect();
	d->connectActObject.disconnect();
	d->connectSaveDocument.disconnect();
	d->connectRestDocument.disconnect();
	d->connectLoadDocument.disconnect();

	// e.g. if document gets closed from within a Python command
	d->_isClosing = true;
	// calls Document::detachView() and alter the view list
	std::list<Gui::BaseView*> temp = d->baseViews;
	for(std::list<Gui::BaseView*>::iterator it=temp.begin();it!=temp.end();++it)
		(*it)->deleteSelf();

 	std::map<const App::DocumentObject*,ViewProviderDocumentObject*>::iterator jt;
 	for (jt = d->_ViewProviderMap.begin();jt != d->_ViewProviderMap.end(); ++jt)
 		delete jt->second;
// 	std::map<std::string,ViewProvider*>::iterator it2;
// 	for (it2 = d->_ViewProviderMapAnnotation.begin();it2 != d->_ViewProviderMapAnnotation.end(); ++it2)
// 		delete it2->second;

	// remove the reference from the object
// 	_pcDocPy->setInvalid();
// 	_pcDocPy->DecRef();
	delete d;
}


/** 
 * Adds a separate XML file to the projects file that contains information about the view providers.
 */
void Gui_Document::Save (Base::Writer &writer) const
{
    // It's only possible to add extra information if force of XML is disabled
    if (writer.isForceXML() == false) {
        writer.addFile("GuiDocument.xml", this);
     
        if ( GetApp_Application().GetParameterGroupByPath
            ("User parameter:BaseApp/Preferences/Document")->GetBool("SaveThumbnail",false)) {
            std::list<MDIView*> mdi = getMDIViews();
            for (std::list<MDIView*>::iterator it = mdi.begin(); it != mdi.end(); ++it) {
                if ((*it)->getTypeId().isDerivedFrom(View3DInventor::getClassTypeId())) {
                    View3DInventorViewer* view = static_cast<View3DInventor*>(*it)->getViewer();
//                     d->thumb.setFileName(d->_pcDocument->FileName.getValue());
//                     d->thumb.setSize(128);
//                     d->thumb.setViewer(view);
//                     d->thumb.Save(writer);
                    break;
                }
            }
        }
    }
}

/** 
 * Loads a separate XML file from the projects file with information about the view providers.
 */
void Gui_Document::Restore(Base::XMLReader &reader)
{
    reader.addFile("GuiDocument.xml",this);
    // hide all elements to avoid to update the 3d view when loading data files
    // RestoreDocFile then restores the visibility status again
    std::map<const App::DocumentObject*,ViewProviderDocumentObject*>::iterator it;
    for (it = d->_ViewProviderMap.begin(); it != d->_ViewProviderMap.end(); ++it) {
        it->second->hide();
        it->second->startRestoring();
    }
}


/**
 * Saves the properties of the view providers.
 */
void Gui_Document::SaveDocFile (Base::Writer &writer) const
{
    writer.Stream() << "<?xml version='1.0' encoding='utf-8'?>" << std::endl
                    << "<!--" << std::endl
                    << " FreeCAD Document, see http://free-cad.sourceforge.net for more information..."
                    << std::endl << "-->" << std::endl;

    writer.Stream() << "<Document SchemaVersion=\"1\">" << std::endl;

    std::map<const App::DocumentObject*,ViewProviderDocumentObject*>::const_iterator it;

    // writing the view provider names itself
    writer.incInd(); // indention for 'ViewProviderData Count'
    writer.Stream() << writer.ind() << "<ViewProviderData Count=\"" 
                    << d->_ViewProviderMap.size() <<"\">" << std::endl;

    bool xml = writer.isForceXML();
    //writer.setForceXML(true);
    writer.incInd(); // indention for 'ViewProvider name'
    for(it = d->_ViewProviderMap.begin(); it != d->_ViewProviderMap.end(); ++it) {
        const App::DocumentObject* doc = it->first;
        ViewProvider* obj = it->second;
        writer.Stream() << writer.ind() << "<ViewProvider name=\""
                        << doc->getNameInDocument() << "\">" << std::endl;
        obj->Save(writer);
        writer.Stream() << writer.ind() << "</ViewProvider>" << std::endl;
    }
    writer.setForceXML(xml);

    writer.decInd(); // indention for 'ViewProvider name'
    writer.Stream() << writer.ind() << "</ViewProviderData>" << std::endl;
    writer.decInd();  // indention for 'ViewProviderData Count'

    // set camera settings
    QString viewPos;
    if (d->_pcAppWnd->sendHasMsgToActiveView("GetCamera")) {
        const char* ppReturn=0;
        d->_pcAppWnd->sendMsgToActiveView("GetCamera",&ppReturn);
  
        // remove the first line because it's a comment like '#Inventor V2.1 ascii'
        QStringList lines = QString(QString::fromAscii(ppReturn)).split(QLatin1String("\n"));
        if (lines.size() > 1) {
            lines.pop_front();
            viewPos = lines.join(QLatin1String(" "));
        }
    }

    writer.incInd(); // indention for camera settings
    writer.Stream() << writer.ind() << "<Camera settings=\"" 
                    << (const char*)viewPos.toAscii() <<"\"/>" << std::endl;
    writer.decInd(); // indention for camera settings
    writer.Stream() << "</Document>" << std::endl;
}


ViewProvider *Gui_Document::getViewProviderByName(const char* name) const
{
	// first check on feature name
	App::DocumentObject *pcFeat = getDocument()->getObject(name);

	if (pcFeat)
	{
		std::map<const App::DocumentObject*,ViewProviderDocumentObject*>::const_iterator
			it = d->_ViewProviderMap.find( pcFeat );

		if (it != d->_ViewProviderMap.end())
			return it->second;
	} else {
		// then try annotation name
		std::map<std::string,ViewProvider*>::const_iterator it2 = d->_ViewProviderMapAnnotation.find( name );

		if (it2 != d->_ViewProviderMapAnnotation.end())
			return it2->second;
	}

	return 0;
}


/**
 * Restores the properties of the view providers.
 */
void Gui_Document::RestoreDocFile(Base::Reader &reader)
{
    // We must create an XML parser to read from the input stream
    Base::XMLReader xmlReader("GuiDocument.xml", reader);

    int i,Cnt;

    xmlReader.readElement("Document");
    long scheme = xmlReader.getAttributeAsInteger("SchemaVersion");

    // At this stage all the document objects and their associated view providers exist.
    // Now we must restore the properties of the view providers only.
    //
    // SchemeVersion "1"
    if (scheme == 1) {
        // read the viewproviders itself
        xmlReader.readElement("ViewProviderData");
        Cnt = xmlReader.getAttributeAsInteger("Count");
        for (i=0 ;i<Cnt ;i++) {
            xmlReader.readElement("ViewProvider");
            std::string name = xmlReader.getAttribute("name");
            ViewProvider* pObj = getViewProviderByName(name.c_str());
            if (pObj) // check if this feature has been registered
                pObj->Restore(xmlReader);
            xmlReader.readEndElement("ViewProvider");
        }
        xmlReader.readEndElement("ViewProviderData");

        // read camera settings
        xmlReader.readElement("Camera");
        const char* ppReturn = xmlReader.getAttribute("settings");
        std::string sMsg = "SetCamera ";
        sMsg += ppReturn;
        if (strcmp(ppReturn, "") != 0) { // non-empty attribute
            if (d->_pcAppWnd->sendHasMsgToActiveView("SetCamera"))
                d->_pcAppWnd->sendMsgToActiveView(sMsg.c_str());
        }
    }

    xmlReader.readEndElement("Document");

    // In the file GuiDocument.xml new data files might be added
    if (!xmlReader.getFilenames().empty())
        xmlReader.readFiles(static_cast<zipios::ZipInputStream&>(reader));

    // reset modifeid flag
    setModified(false);
}



bool Gui_Document::save(void)
{
	if (d->_pcDocument->isSaved()) {
		//Gui::WaitCursor wc;
// 		Command::doCommand(Command::Doc,"App.Document.save()"
// 			,d->_pcDocument->getName());
		Command::doCommand((CommandStringFunction)App::Document::savecmo,d->_pcDocument->getName());
		setModified(false);
		return true;
	}
	else {
		return saveAs();
	}
}

void Gui_Document::setModified(bool b)
{
 	d->_isModified = b;
// 
// 	d->passiveViews
// 
// 	std::list<MDIView*> mdis = getMDIViews();
// 	for (std::list<MDIView*>::iterator it = mdis.begin(); it != mdis.end(); ++it) {
// 		(*it)->setWindowModified(b);
// 	}
}

void Gui_Document::onUpdate(void)
{
// #ifdef FC_LOGUPDATECHAIN
// 	Base::Console().Log("Acti: Gui::Document::onUpdate()");
// #endif
// 
// 	std::list<Gui::BaseView*>::iterator it;
// 
// 	for (it = d->baseViews.begin();it != d->baseViews.end();++it) {
// 		(*it)->onUpdate();
// 	}
// 
// 	for (it = d->passiveViews.begin();it != d->passiveViews.end();++it) {
// 		(*it)->onUpdate();
// 	}
}


bool Gui_Document::isModified() const
{
	return d->_isModified;
}

void Gui_Document::attachView(Gui::BaseView* pcView, bool bPassiv)
{
	if (!bPassiv)
		d->baseViews.push_back(pcView);
	else
		d->passiveViews.push_back(pcView);
}

void Gui_Document::detachView(Gui::BaseView* pcView, bool bPassiv)
{
	if (bPassiv) {
		if (find(d->passiveViews.begin(),d->passiveViews.end(),pcView)
			!= d->passiveViews.end())
			d->passiveViews.remove(pcView);
	}
	else {
		if (find(d->baseViews.begin(),d->baseViews.end(),pcView)
			!= d->baseViews.end())
			d->baseViews.remove(pcView);

		// last view?
// 		if (d->baseViews.size() == 0) {
// 			// decouple a passive view
// 			std::list<Gui::BaseView*>::iterator it = d->passiveViews.begin();
// 			while (it != d->passiveViews.end()) {
// 				(*it)->setDocument(0);
// 				it = d->passiveViews.begin();
// 			}

			// is already  closing the document
// 			if (d->_isClosing == false)
// 				d->_pcAppWnd->onLastWindowClosed(this);
		}
	//}
}

/// Save the document under a new file name
bool Gui_Document::saveAs(void)
{
	getMainWindow()->statusBar()->showMessage(QObject::tr("Save document under new filename..."));

	QString exe = QString::fromUtf8(GetApp_Application().getExecutableName());
	QString fn = QFileDialog::getSaveFileName(getMainWindow(), QObject::tr("Save %1 Document").arg(exe), 
		FileDialog::getWorkingDirectory(), QObject::tr("%1 document (*.cmo)").arg(exe));
	if (!fn.isEmpty()) {
		FileDialog::setWorkingDirectory(fn);
		QString file = fn.toLower();
		if (!file.endsWith(QLatin1String(".cmo"))) {
			fn += QLatin1String(".cmo");
			QFileInfo fi;
			fi.setFile(fn);
			if (fi.exists()) {
				// if we auto-append the extension make sure that we don't override an existing file
				int ret = QMessageBox::question(getMainWindow(), QObject::tr("Save As"), 
					QObject::tr("%1 already exists.\n"
					"Do you want to replace it?").arg(fn),
					QMessageBox::Yes|QMessageBox::Default,
					QMessageBox::No|QMessageBox::Escape); 
				if (ret != QMessageBox::Yes)
					fn = QString();
			}
		}
	}

	if (!fn.isEmpty()) {
		QFileInfo fi;
		fi.setFile(fn);
		QString bn = fi.baseName();

		const char * DocName = GetApp_Application().getDocumentName(getDocument());

		// save as new file name

		GetApp_Application().getActiveDocument()->FileName.setValue((const char*)fn.toUtf8());
		GetApp_Application().getActiveDocument()->Label.setValue((const char*)bn.toUtf8()) ;
	//	Gui::WaitCursor wc;
//  		Command::doCommand(Command::Doc,"App.getDocument(\"%s\").FileName = \"%s\""
//  			, (const char*)fn.toUtf8());
// 		Command::doCommand(Command::Doc,"App.getDocument(\"%s\").Label = \"%s\""
// 			,  (const char*)bn.toUtf8());
// 		Command::doCommand(Command::Doc,"App.Document.save()"
// 			, fn.toAscii());

		Command::doCommand((CommandStringFunction)App::Document::savecmo,fn.toAscii());
		setModified(false);

		getMainWindow()->appendRecentFile(fi.filePath());
		return true;
	}
	else {
		getMainWindow()->statusBar()->showMessage(QObject::tr("Saving aborted"), 2000);
		return false;
	}
}



App::Document* Gui_Document::getDocument(void) const
{
	return d->_pcDocument;
}

void Gui_Document::clearScene()
{
	GetApp_Application().getActiveDocument()->restore();
	//CCustomPlayer::Instance->clearScene();
}
//*****************************************************************************************************
// Document
//*****************************************************************************************************
void Gui_Document::slotNewObject(const App::DocumentObject& Obj)
{
   // Base::Console().Log("Document::slotNewObject() called\n");
     std::string cName = Obj.getViewProviderName();
     if (cName.empty()) {
         // handle document object with no view provider specified
       //  Base::Console().Log("%s has no view provider specified\n", Obj.getTypeId().getName());
         return;
     }
   
     setModified(true);
     Base::BaseClass* base = static_cast<Base::BaseClass*>(Base::Type::createInstanceByName(cName.c_str(),true));
     if (base) {
         // type not derived from ViewProviderDocumentObject!!!
         assert(base->getTypeId().isDerivedFrom(Gui::ViewProviderDocumentObject::getClassTypeId()));
         ViewProviderDocumentObject *pcProvider = static_cast<ViewProviderDocumentObject*>(base);
         d->_ViewProviderMap[&Obj] = pcProvider;
 
        // try {
             // if succesfully created set the right name and calculate the view
             //FIXME: Consider to change argument of attach() to const pointer
             pcProvider->attach(const_cast<App::DocumentObject*>(&Obj));
             pcProvider->updateView();
             pcProvider->setActiveMode();
//          }
//          catch(const Base::MemoryException& e){
//              Base::Console().Error("Memory exception in '%s' thrown: %s\n",Obj.getNameInDocument(),e.what());
//          }
//          catch(Base::Exception &e){
//              e.ReportException();
//          }
//  #ifndef FC_DEBUG
//          catch(...){
//              Base::Console().Error("App::Document::_RecomputeFeature(): Unknown exception in Feature \"%s\" thrown\n",Obj.getNameInDocument());
//          }
//  #endif
         std::list<Gui::BaseView*>::iterator vIt;
         // cycling to all views of the document
         for (vIt = d->baseViews.begin();vIt != d->baseViews.end();++vIt) {
             View3DInventor *activeView = dynamic_cast<View3DInventor *>(*vIt);
             if (activeView)
                 activeView->getViewer()->addViewProvider(pcProvider);
         }
     
         // adding to the tree
         signalNewObject(*pcProvider);
     }
     else {
         Base::Console().Warning("Gui::Document::slotNewObject() no view provider for the object %s found\n",cName.c_str());
     }
}
ViewProvider* Gui_Document::getViewProvider(const App::DocumentObject* Feat) const
{
	std::map<const App::DocumentObject*,ViewProviderDocumentObject*>::const_iterator
		it = d->_ViewProviderMap.find( Feat );
	return ( (it != d->_ViewProviderMap.end()) ? it->second : 0 );
}


void Gui_Document::slotDeletedObject(const App::DocumentObject& Obj)
{
     std::list<Gui::BaseView*>::iterator vIt;
     setModified(true);
     //Base::Console().Log("Document::slotDeleteObject() called\n");
   
     // cycling to all views of the document
     ViewProvider* viewProvider = getViewProvider(&Obj);
     for (vIt = d->baseViews.begin();vIt != d->baseViews.end();++vIt) {
         View3DInventor *activeView = dynamic_cast<View3DInventor *>(*vIt);
         if (activeView && viewProvider) {
             if (d->_pcInEdit == viewProvider)
                 resetEdit();
             activeView->getViewer()->removeViewProvider(viewProvider);
         }
     }
 
     if (viewProvider && viewProvider->getTypeId().isDerivedFrom(
         ViewProviderDocumentObject::getClassTypeId())) {
         // removing from tree
         signalDeletedObject(*(static_cast<ViewProviderDocumentObject*>(viewProvider)));
 
         delete viewProvider;
         d->_ViewProviderMap.erase(&Obj);
     }
}

void Gui_Document::slotChangedObject(const App::DocumentObject& Obj, const App::Property& Prop)
{
    Base::Console().Log("Document::slotChangedObject() called\n");
     ViewProvider* viewProvider = getViewProvider(&Obj);
     if (viewProvider) {
      //   try {
             viewProvider->update(&Prop);
// 			 if(strcmp(Prop.getName(),"VrmlFile") == 0)
// 				updataDocumentObjectMaterial(&Obj); 
//          } catch(const Base::MemoryException& e) {
//              Base::Console().Error("Memory exception in '%s' thrown: %s\n",Obj.getNameInDocument(),e.what());
//          } catch(Base::Exception &e){
//              e.ReportException();
//          } catch (...) {
//              Base::Console().Error("Cannot update representation for '%s'.\n", Obj.getNameInDocument());
//          }
 
         if (viewProvider->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId()))
             signalChangedObject(static_cast<ViewProviderDocumentObject&>(*viewProvider), Prop);
     }
 
     // a property of an object has changed
     setModified(true);
}

void Gui_Document::slotRenamedObject(const App::DocumentObject& Obj)
{
//     ViewProvider* viewProvider = getViewProvider(&Obj);
//     if (viewProvider && viewProvider->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) {
//         signalRenamedObject(*(static_cast<ViewProviderDocumentObject*>(viewProvider)));
//     }
}

void Gui_Document::slotActivatedObject(const App::DocumentObject& Obj)
{
//     ViewProvider* viewProvider = getViewProvider(&Obj);
//     if (viewProvider && viewProvider->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) {
//         signalActivatedObject(*(static_cast<ViewProviderDocumentObject*>(viewProvider)));
//     }
}
void Gui_Document::slotRestoredDocument(const App::Document&)
{
	std::map<const App::DocumentObject*,ViewProviderDocumentObject*>::iterator it;
	for (it = d->_ViewProviderMap.begin(); it != d->_ViewProviderMap.end(); ++it) {
		it->second->finishRestoring();
	}
}


bool Gui_Document::isLastView(void)
{
    if (d->baseViews.size() <= 1)
        return true;
    return false;
}

/** 
 *  This method checks if the document can be closed. It checks on
 *  the save state of the document and is able to abort the closing.
 */
bool Gui_Document::canClose ()
{
    if (!getDocument()->isClosable()) {
        QMessageBox::warning(getActiveView(),
            QObject::tr("Document not closable"),
            QObject::tr("The document is not closable for the moment."));
        return false;
    }
//     else if (!Gui::Control().isAllowedAlterDocument()) {
//         std::string name = Gui::Control().activeDialog()->getDocumentName();
//         if (name == this->getDocument()->getName()) {
//             QMessageBox::warning(getActiveView(),
//                 QObject::tr("Document not closable"),
//                 QObject::tr("The document is in editing mode and thus cannot be closed for the moment.\n"
//                             "You either have to finish or cancel the editing in the task panel."));
//             Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog();
//             if (dlg) Gui::Control().showDialog(dlg);
//             return false;
//         }
//     }

    if (!isModified())
        return true;
    bool ok = true;
    switch(QMessageBox::question(getActiveView(),
        QObject::tr("Unsaved document"),
        QObject::tr("Save document before close?"),
        QMessageBox::Yes | QMessageBox::Default,
        QMessageBox::No,
        QMessageBox::Cancel | QMessageBox::Escape))
    {
    case QMessageBox::Yes:
        ok = save();
        break;
    case QMessageBox::No:
        ok = true;
        break;
    case QMessageBox::Cancel:
        ok = false;
        break;
    }

    return ok;
}



std::list<MDIView*> Gui_Document::getMDIViews() const
{
	std::list<MDIView*> views;
	for (std::list<BaseView*>::const_iterator it = d->baseViews.begin();
		it != d->baseViews.end(); ++it) {
			MDIView* view = dynamic_cast<MDIView*>(*it);
			if (view)
				views.push_back(view);
	}

	return views;
}

bool Gui_Document::setEdit(Gui::ViewProvider* p, int ModNum)
{
	if (d->_pcInEdit)
		resetEdit();
	View3DInventor *activeView = dynamic_cast<View3DInventor *>(getActiveView());
	if (activeView && activeView->getViewer()->setEditingViewProvider(p,ModNum)) {
		d->_pcInEdit = p;
		if (d->_pcInEdit->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) 
			signalInEdit(*(static_cast<ViewProviderDocumentObject*>(d->_pcInEdit)));
	}
	else
		return false;
	return true;
}


void Gui_Document::resetEdit(void)
{
	std::list<Gui::BaseView*>::iterator it;
	if (d->_pcInEdit) {
		for (it = d->baseViews.begin();it != d->baseViews.end();++it) {
			View3DInventor *activeView = dynamic_cast<View3DInventor *>(*it);
			if (activeView)
				activeView->getViewer()->resetEditingViewProvider();
		}

		if (d->_pcInEdit->isDerivedFrom(ViewProviderDocumentObject::getClassTypeId())) 
			signalResetEdit(*(static_cast<ViewProviderDocumentObject*>(d->_pcInEdit)));
		d->_pcInEdit = 0;
	}
}

ViewProvider *Gui_Document::getInEdit(void) const
{
	if (d->_pcInEdit) {
		// there is only one 3d view which is in edit mode
		View3DInventor *activeView = dynamic_cast<View3DInventor *>(getActiveView());
		if (activeView && activeView->getViewer()->isEditingViewProvider())
			return d->_pcInEdit;
	}

	return 0;
}



/// Getter for the active view
MDIView* Gui_Document::getActiveView(void) const
{
	// get the main window's active view 
	MDIView* active = getMainWindow()->activeWindow();

	// get all MDI views of the document
	std::list<MDIView*> mdis = getMDIViews();

	// check whether the active view is part of this document
	bool ok=false;
	for (std::list<MDIView*>::const_iterator it = mdis.begin(); it != mdis.end(); ++it) {
		if ((*it) == active) {
			ok = true;
			break;
		}
	}

	// the active view is not part of this document, just use the first view
	if (!ok && !mdis.empty())
		active = mdis.front();

	return active;
}

unsigned int Gui_Document::getMemSize (void) const
{
	unsigned int size = 0;

	// size of the view providers in the document
// 	std::map<const App::DocumentObject*,ViewProviderDocumentObject*>::const_iterator it;
// 	for (it = d->_ViewProviderMap.begin(); it != d->_ViewProviderMap.end(); ++it)
// 		size += it->second->getMemSize();
	return size;
}
void Gui_Document::createView(const char* sType)
{
  View3DInventor* view3D = new View3DInventor(this, getMainWindow());

  std::map<const App::DocumentObject*,ViewProviderDocumentObject*>::const_iterator It1;
  for (It1=d->_ViewProviderMap.begin();It1!=d->_ViewProviderMap.end();++It1)
	  view3D->getViewer()->addViewProvider(It1->second);


   view3D->setWindowTitle(QString::fromAscii("vrRender"));
   view3D->setWindowIcon(QApplication::windowIcon());
   view3D->resize(400, 300);

  getMainWindow()->addWindow(view3D);
}

void Gui_Document::updataDocumentObjectMaterial(const App::DocumentObject* pObj)
{

	 ViewProvider* viewProvider = getViewProvider(pObj);
	 if(viewProvider && viewProvider->getTypeId().isDerivedFrom(ViewProviderDocumentObject::getClassTypeId()))
	 {
		 static_cast<ViewProviderDocumentObject*>(getViewProvider(pObj))->updateMaterial();

	 }
//  	if(pObj->getTypeId().isDerivedFrom(ViewProviderDocumentObject::getTypeId()))
// 	{
// 	}
}

ViewProvider* Gui_Document::_getObject(const char* name)
{
	return  getViewProviderByName(name);
}


